'''
This file is part of ModeliMark.

ModeliMark is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

ModeliMark is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with ModeliMark.
If not, see <http://www.gnu.org/licenses/>.

Copyright 2011 Jens Frenkel
'''

import wrapper
import numbers
import shlex, subprocess
import os
from time import *

class Dymola(wrapper.BaseWrapper):
    '''
    classdocs
    '''


    def __init__(self,dymolapath,savelog=False):
        '''
        Constructor
        
        :param dymolapath: Path to the Dymola executable.
        :type dymolapath: String.         
        '''
        
        assert(isinstance(dymolapath,str))
        self._dymola = dymolapath 
        self._savelog = savelog
   
    def open(self, model, files):
        '''
        instructs the compiler to open the Modelica 
        code and return, the implementation is only necesarry
        if the compiler uses a window 
        
        :param model: Name of the Model to flatten.
        :type model: String.   
             
        :param files: all Files of the Model.
        :type files: list of String.             
        '''        
        assert(isinstance(model,str))
        assert(isinstance(files,list)) 
        
        # generate mos file
        mosfile = '%s.mos'%(model)
        f = open( mosfile, 'w' )
        for file in files:
            f.write('openModel("%s");\n'%(file))
        if (self._savelog):
            f.write('savelog("s_open.log")\n'%(model));
        f.write('exit();\n')
        # Close File
        f.close()       
        
        #
        logfile = '%s_open_py.log'%(model) 
        res, dt = self._run(logfile,[mosfile])
        if (res == 0):
            res = self._readResult(logfile)
        else:
            res = False
               
        return res, dt      
        
    def flatten(self, model, files):
        '''
        instructs the compiler to parse the Modelica 
        code and return the flat model
        
        :param model: Name of the Model to flatten.
        :type model: String.   
             
        :param files: all Files of the Model to flatten.
        :type files: list of String.             
        '''        
        assert(isinstance(model,str))
        assert(isinstance(files,list))
        
        # generate mos file
        mosfile = '%s.mos'%(model)
        f = open( mosfile, 'w' )
        for file in files:
            f.write('openModel("%s");\n'%(file))
        f.write('checkModel("%s");\n'%(model))
        if (self._savelog):
            f.write('savelog("s_flatten.log")\n'%(model));        
        f.write('exit();\n')
        # Close File
        f.close()       
        
        #
        logfile = '%s_flatten_py.log'%(model) 
        res, dt = self._run(logfile,[mosfile])
        if (res == 0):
            res = self._readResult(logfile)
        else:
            res = False
               
        return res, dt        
      
    def translate(self, model, files):
        '''
        flattens the model and turns it into a state which can be simulated
        
        :param model: Name of the Model to flatten.
        :type model: String.   
             
        :param files: all Files of the Model to flatten.
        :type files: list of String. 
        '''         
        assert(isinstance(model,str))
        assert(isinstance(files,list))      
       
        # generate mos file
        mosfile = '%s.mos'%(model)
        f = open( mosfile, 'w' )
        for file in files:
            f.write('openModel("%s");\n'%(file))
        f.write('translateModel("%s");\n'%(model))
        if (self._savelog):
            f.write('savelog("s_translate.log")\n'%(model));   
        f.write('exit();\n')                 
        # Close File
        f.close()       
        
        #
        logfile = '%s_translate_py.log'%(model) 
        res, dt = self._run(logfile,[mosfile])
        if (res == 0):
            res = self._readResult(logfile)
        else:
            res = False
               
        return res, dt             
        
    def simulate(self, model, files, startTime, outputInterval, stopTime):
        '''
        flattens, translates and simulates the model using the standard solver
        and a predefined output interval and stop time
        
        :param model: Name of the Model to flatten.
        :type model: String.   
             
        :param files: all Files of the Model to flatten.
        :type files: list of String. 
        
        :param startTime: Start Time of the Simulation
        :type startTime: numbers.Real.
                
        :param outputInterval: Intervall for Output of Results.
        :type outputInterval: numbers.Real. 
        
        :param stopTime: Stop Time of the Simulation
        :type stopTime: numbers.Real. 
        '''         
        assert(isinstance(model,str))
        assert(isinstance(files,list))
        assert(isinstance(startTime,numbers.Real))
        assert(isinstance(outputInterval,numbers.Real))
        assert(isinstance(stopTime,numbers.Real))        
        
        # generate mos file
        mosfile = '%s.mos'%(model)
        f = open( mosfile, 'w' )
        for file in files:
            f.write('openModel("%s");\n'%(file))
        f.write('simulateModel("%s", startTime=%s, stopTime=%s, numberOfIntervals=0, outputInterval=%s);\n'%(model,str(startTime),str(stopTime),str(outputInterval)))
        if (self._savelog):
            f.write('savelog("s_simulate.log")\n'%(model));   
        f.write('exit();\n')         
        # Close File
        f.close()       
        
        #
        logfile = '%s_simulate_py.log'%(model) 
        res, dt = self._run(logfile,[mosfile])
        if (res == 0):
            res = self._readResult(logfile)
        else:
            res = False
               
        return res, dt      
   
        
    def _run(self,logfilename,args,cwd=None):
        
        assert(isinstance(logfilename,str))
        
        ar = list()
        ar.append(self._dymola)
        for a in args:
            ar.append(a)
            
        print 'starte Dymola'
        f = open( logfilename, 'w' )
        t1 = clock() 
        p = subprocess.Popen(args=ar,stdout=f,cwd=cwd)
        run = True
        while run:
            res = p.poll()
            if (res is not None):
                run = False        
        t2 = clock() 
        dt = t2 - t1         
        f.close() 
        return res, dt       
        
    def _readResult(self,logfilename):
        
        with open(logfilename, 'r') as f:
            for line in f:
                if (line == ' = false\n'): 
                    return False
#                elif (line == ' = true\n'):
#                    pass
#                else:
#                    print "ignoring %s"%line
        f.close()
        return True                 